package com.starview.star.operators.assignment.runtime;

import com.starview.platform.data.IFunction;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.platform.data.value.Factory;
import com.starview.star.operators.CafeEnter;
import com.starview.star.operators.assignment.runtime.AtomicCell.AtomCell;

public class AtomicOps
{
  public static class AtomReference implements IFunction
  {
    public static final String name = "__atomic_reference";

    @CafeEnter
    public static IValue enter(AtomCell cell)
    {
      return cell.get();
    }

    @Override
    public IValue enter(IValue... args)
    {
      return enter((AtomCell) args[0]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar tv = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(AtomicCell.typeExp(tv), tv));
    }
  }

  public static class AtomicAssignment implements IFunction
  {
    public static final String name = "__atomic_assign";

    @CafeEnter
    public static IValue enter(AtomCell cell, IValue value)
    {
      cell.set(value);
      return StandardTypes.unit;
    }

    @Override
    public IValue enter(IValue... args)
    {
      return enter((AtomCell) args[0], args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar tv = new TypeVar();
      return Refresher.generalize(TypeUtils.procedureType(AtomicCell.typeExp(tv), tv));
    }
  }

  public static class AtomTestAndSwap implements IFunction
  {
    public static final String name = "__atomic_test_n_swap";

    @CafeEnter
    public static IValue enter(AtomCell cell, IValue expected, IValue actual)
    {
      return Factory.newBool(cell.compareAndSet(expected, actual));
    }

    @Override
    public IValue enter(IValue... args)
    {
      return enter((AtomCell) args[0], args[1], args[2]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar tv = new TypeVar();
      return Refresher.generalize(TypeUtils.functionType(AtomicCell.typeExp(tv), tv, tv, StandardTypes.booleanType));
    }
  }

}
